package com.atguigu.tingshu.album.task;

import cn.hutool.core.collection.CollUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author: atguigu
 * @create: 2025-03-21 09:21
 */
@Slf4j
@Component
public class RebuildBloomFilterTask {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 重建布隆过滤器 TODO 后续改为xxl-job 定时+手动调度
     * 周期:每月1号凌晨2点执行
     */
    //@Scheduled(cron = "0/10 * * * * ?")
    @Scheduled(cron = "0 0 2 1 * ?")
    public void rebuildBloomFilter() {
        //1.处理扩容重建情况：布隆过滤器中元素数量大于期望数据规模，造成误判率就会上升
        //1.1 获取"旧"的布隆过滤器对象 得到：期望数据规模、现有元素数量
        RBloomFilter<Long> oldBloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        long expectedInsertions = oldBloomFilter.getExpectedInsertions();
        long count = oldBloomFilter.count();
        double falseProbability = oldBloomFilter.getFalseProbability();
        log.info("[专辑服务]触发重建布隆过滤器任务：现有期望数据规模：{}，现有实际数据量：{}", expectedInsertions, count);
        //1.2 如果满足实际元素数量大于期望数据量，需要扩容
        if (count >= expectedInsertions) {
            log.info("[专辑服务]布隆过滤器扩容");
            //1.2.1 创建/初始化"新"的布隆过滤器 名称="旧":new  期望数据规模：原来的2倍
            RBloomFilter<Long> newBloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER + ":new");
            newBloomFilter.tryInit(expectedInsertions * 2, falseProbability);
            //1.2.2 将过审专辑ID加入到"新"布隆过滤器内
            this.addDataToBloomFilter(newBloomFilter);
            //1.2.3 删除"旧"布隆过滤器 删除配置以及产生位图
            oldBloomFilter.delete();
            //1.2.4 对"新"布隆过滤器重命名 改为"旧"的名称，此时数据已经新的了
            newBloomFilter.rename(RedisConstant.ALBUM_BLOOM_FILTER);
        } else {
            log.info("[专辑服务]布隆过滤器重建");
            //2.不满足扩容条件：重建布隆过滤器.存在一些专辑被删除，被下架，被删除专辑ID仍然存在于布隆过滤器中。
            //2.1 删除原有布隆过滤器，重新初始化新的
            oldBloomFilter.delete();
            RBloomFilter<Long> newBloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            newBloomFilter.tryInit(expectedInsertions, falseProbability);
            //2.2 将过审专辑ID加入到布隆过滤器中
            this.addDataToBloomFilter(newBloomFilter);
        }
    }


    /**
     * 将审核通过专辑ID加入到布隆过滤器
     *
     * @param bloomFilter
     */
    private void addDataToBloomFilter(RBloomFilter<Long> bloomFilter) {
        //1.根据审核条件查询过审专辑ID 得到专辑ID列表
        List<AlbumInfo> albumInfoList = albumInfoMapper
                .selectList(
                        new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS)
                                .select(AlbumInfo::getId)
                );
        if (CollUtil.isNotEmpty(albumInfoList)) {
            //2.循环将专辑ID加入到布隆过滤器
            albumInfoList
                    .stream()
                    .map(AlbumInfo::getId)
                    .forEach(bloomFilter::add);
        }
    }
}
